/*******************************************************************************
 Chatty - Mobile Messaging - J2ME ICQ clone
 Copyright (C) 2003-05  Chatty Project

 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version 2
 of the License, or (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 ********************************************************************************
 File: src/chatty/Chatty.java
 Version: ###VERSION###  Date: ###DATE###
 Author(s): Manuel Linsmayer, Andreas Rossbacher, Vladimir Kryukov
 *******************************************************************************/


package chatty;

import DrawControls.icons.Icon;
import DrawControls.icons.ImageList;

import java.util.Timer;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
import javax.microedition.io.ConnectionNotFoundException;

import chatty.chat.*;
import chatty.cl.*;
import chatty.comm.*;
import chatty.history.*;
import chatty.modules.*;
import chatty.modules.traffic.*;
import chatty.search.Search;
import chatty.ui.*;
import chatty.ui.base.*;
import chatty.ui.timers.*;
import chatty.util.ResBundle;

import protocol.Protocol;


public class Chatty extends MIDlet implements Runnable {
    public static final String VERSION = "###VERSION###";
    public static String lastVersion;
    public static String lastDate;
	public static Image noAvatar;
	public static ImageList icons;
	public static ImageList chatIcons;
	public static ImageList menuIcons;
	public static ImageList optionsIcons;
	public static ImageList formIcons;
	public static ImageList treeIcons;
	
	/* static {
		icons	  = ImageList.createImageList("/icons.png");
		chatIcons = ImageList.createImageList("/chat.png");
		menuIcons = ImageList.createImageList("/menu.png");
		optionsIcons = ImageList.createImageList("/options.png");
		formIcons = ImageList.createImageList("/form.png");
		treeIcons = ImageList.createImageList("/tree.png");
	} */
	
    // Application main object
    private static Chatty chatty = null;
    public static Chatty getChatty() {
        return chatty;
    }

    // Display object
    private Display display = null;
	
	// SelectBox
	public static final byte ICON_F_SB_0    = 0;
	public static final byte ICON_F_SB_1 	= 1;
	// CheckBox
	public static final byte ICON_F_CB_0    = 2;
	public static final byte ICON_F_CB_1    = 3;
	
	public static final byte ICON_F_PEN     = 4;
	
	public static final byte ICON_T_CLOSED  = 0;
	public static final byte ICON_T_OPENED 	= 1;
	public static final byte ICON_T_EMPTY   = 2;
	
	// menu.png
	public static final byte ICON_MENU       = 0;
	public static final byte ICON_CONNECT    = 1;
	public static final byte ICON_DISCONNECT = 2;
	public static final byte ICON_OPTIONS    = 3;
	public static final byte ICON_TRAFFIC    = 4;
	public static final byte ICON_KEYLOCK    = 5;
	public static final byte ICON_GROUPS     = 6;
    public static final byte ICON_SEND_SMS   = 7;
	public static final byte ICON_ABOUT      = 8;
	public static final byte ICON_MINIMIZE   = 9;
	public static final byte ICON_SOUND_ON   = 10;
	public static final byte ICON_SOUND_OFF  = 11;
	public static final byte ICON_MYSELF     = 12;
    public static final byte ICON_MAGIC_EYE  = 13;
	public static final byte ICON_EXIT       = 14;
	public static final byte ICON_HIDE_OFFLINE	= 15;
	public static final byte ICON_SHOW_OFFLINE	= 16;
	
	// icons.png
	public static final byte ICON_USER_INFO			= 0;
	public static final byte ICON_MANAGE_CONTACT	= 1;
	public static final byte ICON_HISTORY			= 2;
	public static final byte ICON_USER_ADD			= 3;
	public static final byte ICON_USER_RENAME		= 4;
	public static final byte ICON_USER_MOVE			= 5;
	public static final byte ICON_USER_REMOVE		= 6;
	public static final byte ICON_USER_REMOVE_ME	= 7;
	public static final byte ICON_USER_SEARCH		= 8;
	public static final byte ICON_GROUP_ADD			= 9;
	public static final byte ICON_GROUP_RENAME		= 10;
	public static final byte ICON_GROUP_REMOVE		= 11;
	public static final byte ICON_AUTH_GRANT		= 12;
	public static final byte ICON_AUTH_DENY			= 13;
	public static final byte ICON_PREV				= 14;
	public static final byte ICON_NEXT				= 15;
	public static final byte ICON_TRANS_FILE		= 16;
	public static final byte ICON_TRANS_CAM			= 17;
	public static final byte ICON_ADD_TO_HISTORY	= 18;
	public static final byte ICON_REPLY				= 19;
	public static final byte ICON_EXTRA				= 20;
	public static final byte ICON_NEW_MSG			= 21;
	public static final byte ICON_INFO				= 22;
	public static final byte ICON_PROPERTIES		= 23;
	public static final byte ICON_FIND				= 24;
	public static final byte ICON_BACK				= 25;
	public static final byte ICON_ADD				= 26;
	public static final byte ICON_DEL				= 27;
	public static final byte ICON_EDIT				= 28;
	public static final byte ICON_ON   			    = 29;
	public static final byte ICON_OFF			    = 30;
	public static final byte ICON_AVATAR            = 31;
	
	// chat.png
	public static final byte ICON_COPY			= 0;
	public static final byte ICON_COPY_ADD	    = 1;
	public static final byte ICON_COPY_ALL		= 2;
	public static final byte ICON_CUT			= 3;
	public static final byte ICON_PASTE			= 4;
	public static final byte ICON_QUOTE			= 5;
	public static final byte ICON_CLEAR			= 6;
	public static final byte ICON_SMILES		= 7;
	public static final byte ICON_TEMPLATES		= 8;
	public static final byte ICON_GOTO_URL		= 9;
	public static final byte ICON_USER_MENU		= 10;
	public static final byte ICON_DEL_CHAT		= 11;
	
	// options.png
	public static final byte ICON_ACCOUNT		= 0;
	public static final byte ICON_NETWORK		= 1;
	public static final byte ICON_INTERFACE		= 2;
	public static final byte ICON_SCHEME		= 3;
	public static final byte ICON_SKIN			= 4;
	public static final byte ICON_HOTKEYS		= 5;
	public static final byte ICON_SIGNALING		= 6;
	public static final byte ICON_LIGHT     	= 7;
    public static final byte ICON_ABSENCE       = 8;
	public static final byte ICON_TIMEZONE		= 9;
	public static final byte ICON_ANTISPAM		= 10;
	public static final byte ICON_ANSWERER		= 11;
	
    /****************************************************************************/

    public static final byte PHONE_SE             = 0;
    public static final byte PHONE_SE_SYMBIAN     = 1;
    public static final byte PHONE_NOKIA          = 2;
    public static final byte PHONE_NOKIA_S40      = 3;
    public static final byte PHONE_NOKIA_S60      = 4;
    public static final byte PHONE_NOKIA_N80      = 5;
    public static final byte PHONE_INTENT_JTE     = 6;
    public static final byte PHONE_JBED           = 7;
    public static final byte PHONE_SIEMENS_SGOLG2 = 8;
    public static final byte PHONE_SAMSUNG        = 9;
    public static final byte PHONE_ANDROID        = 10;
   
	public static Icon getFormIcon(byte index) {
        return formIcons.iconAt(index);
    }
	public static Icon getTreeIcon(byte index) {
        return treeIcons.iconAt(index);
    }

    public static final String getPhone() {
        final String platform = getSystemProperty("microedition.platform", null);
        // #sijapp cond.if target is "MIDP2" #
        if (null == platform) {
            try {
                Class.forName("com.nokia.mid.ui.DeviceControl");
                return "Nokia";
            } catch (Exception e) {
            }
        }
        // #sijapp cond.elseif target is "MOTOROLA" #
        if (null == platform) {
            return "Motorola";
        }
        // #sijapp cond.end #
        // #sijapp cond.if modules_ANDROID is "true" #
        String android = getSystemProperty("device.model", "")
                + "/" + getSystemProperty("device.software.version", "")
                + "/" +  getSystemProperty("device.id", "");
        if (2 < android.length()) {
            return "android/" + android;
        }
        // #sijapp cond.end #
        return platform;
    }
    
    public static final String microeditionPlatform = getPhone();
    public static final String microeditionProfiles = getSystemProperty("microedition.profiles", null);
    // #sijapp cond.if target is "MIDP2"#
    public static final byte generalPhoneType = getGeneralPhone();

    private static byte getGeneralPhone() {
        String device = getPhone();
        if (null == device) {
            return -1;
        }
        device = device.toLowerCase();
        // #sijapp cond.if target is "MIDP2" #
        // #sijapp cond.if modules_ANDROID is "true" #
        if (-1 != device.indexOf("android")) {
            return PHONE_ANDROID;
        }
        // #sijapp cond.end#
        if (device.indexOf("ericsson") != -1) {
            if ((-1 != getSystemProperty("com.sonyericsson.java.platform", "")
                        .toLowerCase().indexOf("sjp"))) {
                return PHONE_SE_SYMBIAN;
            }
            return PHONE_SE;
        }
        if (-1 != device.indexOf("platform=s60")) {
            return PHONE_NOKIA_S60;
        }
        if (device.indexOf("nokia") != -1) {
            if (device.indexOf("nokian80") != -1) {
                return PHONE_NOKIA_N80;
            }
            String dir = getSystemProperty("fileconn.dir.private", "");
            // s40 (6233) does not have this property
            if (-1 != dir.indexOf("/private/")) {
                // it is s60 v3 fp1
                return PHONE_NOKIA_S60;
            }
            // Nokia s40 has only one dot into version
            int firstDotIndex = device.indexOf('.');
            if (-1 != firstDotIndex) {
                if (-1 != device.indexOf('.', firstDotIndex + 1)) {
                    return PHONE_NOKIA_S60;
                }
            }
            return PHONE_NOKIA_S40;
        }
        if (device.indexOf("samsung") != -1) {
            return PHONE_SAMSUNG;
        }
        if (device.indexOf("jbed") != -1) {
            return PHONE_JBED;
        }
        if (device.indexOf("intent") != -1) {
            return PHONE_INTENT_JTE;
        }
        // #sijapp cond.end #
        return -1;
    }
    public static boolean isPhone(final byte phone) {
        // #sijapp cond.if target is "MIDP2" #
        if (PHONE_NOKIA == phone) {
            return (PHONE_NOKIA_S40 == generalPhoneType)
                    || (PHONE_NOKIA_S60 == generalPhoneType)
                    || (PHONE_NOKIA_N80 == generalPhoneType);
        }
        if (PHONE_SE == phone) {
            return (PHONE_SE_SYMBIAN == generalPhoneType)
                    || (PHONE_SE == generalPhoneType);
        }
        // #sijapp cond.end #
        return phone == generalPhoneType;
    }
    // #sijapp cond.end #
    public static boolean hasMemory(int requared) {
        // #sijapp cond.if target is "MIDP2" #
        if (isPhone(PHONE_SE)) {
            return true;
        }
        if (isPhone(PHONE_NOKIA_S60)) {
            return true;
        }
        if (isPhone(PHONE_JBED)) {
            return true;
        }
        if (isPhone(PHONE_INTENT_JTE)) {
            return true;
        }
        // #sijapp cond.if modules_ANDROID is "true" #
        if (isPhone(PHONE_ANDROID)) {
            return true;
        }
        // #sijapp cond.end #
        // #sijapp cond.end #
        System.gc();
        long free = Runtime.getRuntime().freeMemory();
        return (requared < free);
    }

    public static String getAppProperty(String key, String defval) {
        String res = null;
        try {
            res = chatty.getAppProperty(key);
        } catch (Exception e) {
        }
        return StringConvertor.isEmpty(res) ? defval : res;
    }
    public static boolean isSetAppProperty(String key) {
        String res = getAppProperty(key, "");
        return "yes".equals(res) || "true".equals(res);
    }
    private static String getSystemProperty(String key, String defval) {
        String res = null;
        try {
            res = System.getProperty(key);
        } catch (Exception e) {
        }
        return StringConvertor.isEmpty(res) ? defval : res;
    }

    // #sijapp cond.if target is "MIDP2"#
    public static boolean isS60v5() {
        String platform = StringConvertor.notNull(Chatty.microeditionPlatform);
        return -1 != platform.indexOf("sw_platform_version=5.0");
    }
    // #sijapp cond.end#
    // #sijapp cond.if target is "MIDP2" | target is "MOTOROLA" #
    private static void platformRequestUrl(String url) throws ConnectionNotFoundException {

        if (url.equals("chatty:update")) {
            StringBuffer url_ = new StringBuffer();
            url_.append("http://jimm.net.ru/go.xhtml?act=update&lang=");
            url_.append(ResBundle.getCurrUiLanguage());
            url_.append("&protocols=###PROTOCOLS###&cdata=");
            url_.append(Config.loadResource("build.dat"));
            url = url_.toString();
        }
        Chatty.getChatty().platformRequest(url.trim());
    }
    public static void openUrl(String url) {
        try {
            platformRequestUrl(url);
        } catch (Exception e) {
            /* Do nothing */
        }
    }
    public static void platformRequestAndExit(String url) {
        try {
            platformRequestUrl(url);
            Chatty.getChatty().quit();
        } catch (Exception e) {
            /* Do nothing */
        }
    }
    // #sijapp cond.end #
    


    public void run() {
        try {
            // #sijapp cond.if modules_TRAFFIC is "true" #
            // Create traffic Object (and update progress indicator)
            Traffic.getInstance().load();
            // #sijapp cond.end#
            // #sijapp cond.if modules_SOUND is "true"#
            // #sijapp cond.if target is "MIDP2" | target is "MOTOROLA"#
            Notify.getSound().initSounds();
            // #sijapp cond.end#
            // #sijapp cond.end#
            // #sijapp cond.if modules_LIGHT is "true" #
            CustomLight.switchOn(Options.getBoolean(Options.OPTION_LIGHT));
            // #sijapp cond.end#

            System.gc();
        } catch (Exception e) {
            e.printStackTrace();
        }
        // #sijapp cond.if modules_DEBUGLOG is "true"#
        DebugLog.startTests();
        // #sijapp cond.end#
    }
    private void initialize() {
        ResBundle.loadLanguageList();

        Options.loadOptions();
        ResBundle.setCurrUiLanguage(Options.getString(Options.OPTION_UI_LANGUAGE));
        Options.resetLangDependedOpts();

        NativeCanvas.setFullScreen(true);
        Scheme.load();
        Scheme.setColorScheme(Options.getInt(Options.OPTION_COLOR_SCHEME));
		
		//Skin.load();
        //Skin.setSkin(Options.getInt(Options.OPTION_SKIN));
		
        GraphicsEx.setFontScheme(Options.getInt(Options.OPTION_FONT_SCHEME));
        UIUpdater.startUIUpdater();

        SplashCanvas.setMessage(ResBundle.getString("loading"));
        SplashCanvas.showSplash();
        SplashCanvas.setProgress(5);

        // back loading (traffic, sounds and light)
        new Thread(this).start();
        // Get display object (and update progress indicator)
		try {
			noAvatar = Image.createImage("/no_avatar.png");
		} catch (OutOfMemoryError er) {
		} catch (Exception e) {
		}
		icons	  = ImageList.createImageList("/icons.png");
		chatIcons = ImageList.createImageList("/chat.png");
		menuIcons = ImageList.createImageList("/menu.png");
		optionsIcons = ImageList.createImageList("/options.png");
		formIcons = ImageList.createImageList("/form.png");
		treeIcons = ImageList.createImageList("/tree.png");
		
        // init message editor
        SplashCanvas.setProgress(10);
        // #sijapp cond.if modules_SMILES is "true" #
        Emotions.instance.load();
        // #sijapp cond.end#
		
        SplashCanvas.setProgress(25);
        StringConvertor.load();
        
		// Modules load
		SplashCanvas.setProgress(35);
		Templates.getInstance().load();
		Answerer.getInstance().load();
		
        // init contact list
        SplashCanvas.setProgress(45);
        Options.loadAccounts();
        SplashCanvas.setProgress(70);
		ContactList.getInstance().initUI();
        SplashCanvas.setProgress(80);
        ContactList.getInstance().initAccounts();
    }

    private boolean paused = true;
    private void restore() {
//        UIUpdater.startUIUpdater();
//        // #sijapp cond.if modules_LIGHT is "true" #
//        CustomLight.switchOn(false);
//        CustomLight.switchOn(Options.getBoolean(Options.OPTION_LIGHT));
//        CustomLight.setLightMode(CustomLight.ACTION_SYSTEM_OFF);
//        // #sijapp cond.end#
        // #sijapp cond.if modules_ABSENCE is "true" #
        AutoAbsence.instance.online();
        // #sijapp cond.end #
        paused = false;
        if (null == currentScreen) {
            //setDisplayable(null);
            //ContactList.activateContactList();
            return;
        }
        Displayable d = chatty.display.getCurrent();
        if (null == d) {
            if (currentScreen instanceof CanvasEx) {
                d = NativeCanvas.getInstance();
            }
        }
        if (null != d) {
            // #sijapp cond.if target is "MIDP2"#
            if (isS60v5()) {
                setDisplayable(null);
            }
            // #sijapp cond.end#
            setDisplayable(d);
        }
    }
    
    public Display getDisplay() {
        return display;
    }

    // Start Chatty
    public void startApp() throws MIDletStateChangeException {
        if (!paused && (null != Chatty.chatty)) {
            return;
        }
        paused = false;
        if (null == display) {
            display = Display.getDisplay(this);
        }
        // Return if MIDlet has already been initialized
        if (null != Chatty.chatty) {
            restore();
            return;
        }
        locked = false;
        // Save MIDlet reference
        Chatty.chatty = this;

        initialize();
        
        // #sijapp cond.if target is "MIDP2" | target is "MOTOROLA"#
        if (GetVersion.showUpdates()) {
            ContactList.activateContactList();
            PopupWindow.createNewVersion().show();
            return;
        }
        // #sijapp cond.end#
        
        // Activate contact list
        ContactList.getInstance().startUp();
    }

    // Pause
    public void pauseApp() {
        hideApp();
    }
    public void hideApp() {
        paused = true;
        if (currentScreen instanceof InputTextBox) {
            return;
        }
        //currentScreen = null;
        locked = false;
        // #sijapp cond.if modules_ABSENCE is "true" #
        AutoAbsence.instance.away();
        // #sijapp cond.end #
    }

    public void quit() {
        ContactList cl = ContactList.getInstance();
        boolean wait = false;
        try {
        if (cl.isConnected()) {
            cl.disconnect();
            wait = true;
        }
        } catch (Exception e) {
            return;
        }
        try {
            Thread.sleep(100);
        } catch (InterruptedException e1) {
            /* Do nothing */
        }
        cl.safeSave();
        if (wait) {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e1) {
                /* Do nothing */
            }
        }
        try {
            Chatty.getChatty().destroyApp(true);
        } catch (Exception e) {
            /* Do nothing */
        }
    }
    /**
     * Destroy Chatty
     */
    public void destroyApp(boolean unconditional) throws MIDletStateChangeException {
        // #sijapp cond.if modules_TRAFFIC is "true" #
        // Save traffic
        Traffic.getInstance().safeSave();
        // #sijapp cond.end#
        chatty.display.setCurrent(null);
        notifyDestroyed();
    }

    public static void setDisplayable(Displayable d) {
        chatty.display.setCurrent(d);
    }
    private Object currentScreen = null;
    public static void setDisplay(Object d) {
        if (chatty.paused) {
            return;
        }
        NativeCanvas.stopKeyRepeating();

        if (chatty.currentScreen instanceof DisplayableEx) {
            ((DisplayableEx)chatty.currentScreen).closed();

        // #sijapp cond.if modules_LIGHT is "true" #
        } else if ((chatty.currentScreen instanceof Displayable)) {
            CustomLight.setLightMode(CustomLight.ACTION_SYSTEM_OFF);
        // #sijapp cond.end#
        }

        synchronized (chatty) {
            if (d instanceof DisplayableEx) {                
                ((DisplayableEx)d).setDisplayableToDisplay();
                chatty.currentScreen = d;

            } else if (d instanceof Displayable) {
                // #sijapp cond.if modules_LIGHT is "true" #
                CustomLight.setLightMode(CustomLight.ACTION_SYSTEM);
                // #sijapp cond.end#
                setDisplayable((Displayable)d);
                chatty.currentScreen = d;

            // #sijapp cond.if modules_DEBUGLOG is "true" #
            // #sijapp cond.if target is "MIDP2"#
            } else if ((null == d) && Chatty.isPhone(Chatty.PHONE_SE)) {
                DebugLog.panic("displayable object is null");
            // #sijapp cond.end#

            } else if (null != d) {
                DebugLog.panic("not displayable object is " + d.getClass().getName());
            // #sijapp cond.end#
            }
        }
    }
    public static Object getCurrentDisplay() {
        return chatty.currentScreen;
    }

    public static void setPrevDisplay() {
        Object screen = chatty.currentScreen;
        if (screen instanceof DisplayableEx) {
            ((DisplayableEx)screen).back();
        }
    }
    public static boolean isPaused() {
        if (chatty.paused) {
            return true;
        }
        Displayable d = chatty.display.getCurrent();
        return (null == d) || !d.isShown();
    }

    private boolean locked = false;
    public static boolean isLocked() {
        return chatty.locked;
    }
    
    public static void lockChatty() {
        chatty.locked = true;
        SplashCanvas.instance.lockChatty();
        // #sijapp cond.if modules_ABSENCE is "true" #
        AutoAbsence.instance.away();
        // #sijapp cond.end #
    }
    public static void unlockChatty() {
        chatty.locked = false;
        ContactList.activateContactList();
        UIUpdater.refreshClock();
        // #sijapp cond.if modules_ABSENCE is "true" #
        AutoAbsence.instance.online();
        // #sijapp cond.end #
    }
    
    // #sijapp cond.if target is "MIDP2" #
    // Set the minimize state of midlet
    public static void setMinimized(boolean mini) {
        // #sijapp cond.if target is "MIDP2" #
        if (mini) {
            chatty.hideApp();
            setDisplayable(null);

        } else {
            try{
                chatty.paused = isPaused();
                chatty.startApp();
            } catch(Exception exc1) {
            }
            chatty.paused = false;
        }
        // #sijapp cond.end #
    }
    // #sijapp cond.end #
}